home *** CD-ROM | disk | FTP | other *** search
- ;************************************************************************
- ; *
- ; PARALLEL PRINTER DRIVER *
- ; *
- ; Written by Don Fletcher *
- ; *
- ;************************************************************************
- ;
- ;
- ;================== DEVICE HEADER BLOCK =================================
- ;
- ; All device drivers start with a defined 18 byte block
- ; of data called the 'Device Header', which must start at
- ; origin 0 within the device driver segment.
- ;
- CODE SEGMENT PUBLIC 'CODE'
- DEVICE Proc far
- ASSUME CS:CODE,DS:CODE,ES:CODE
- ;
- Org 0
- ;
- ; Data Constants
- ;
- ; If you have a monochrome display and printer adapter,
- ; add 44H to the three addresses that follow.
- ;
- Print_Dat Equ 378H ;or 3BCH - Printer data port
- Print_Stat Equ 379H ;or 3BDH - Printer status port
- Print_Out Equ 37AH ;or 3BEH - Status output port
- ;
- Busy Equ 80H ;Busy test mask
- Strobe_Hi Equ 0DH ;Strobe output high
- Strobe_Low Equ 0CH ;Strobe output low
- ;
- ;
- ;
- ; Within this 'Device Header' block must be:
- ;
- ; 1) The Device Chain Pointer -- Double word, set to -1,-1
- ; (FFFF:FFFF) in your code. MS-DOS uses this location
- ; for a double wide pointer to the next device in the
- ; chain.
- ;
- DW -1,-1 ;Pointer to the next device
- ;
- ; 2) The Device Header Attribute word -- 16 single bit fields
- ; that tell MS-DOS the type and capabilities of the device
- ; driver. We will use the standard character device for
- ; our printer driver - 8000H.
- ;
- DW 8000H ;Standard Character device
- ;
- ; 3) The Strategy entry pointer -- Holds the entry offset
- ; address if the Strategy code. Since the offset is only
- ; 16 bits, the strategy code must be in the same segment as
- ; the device header block.
- ;
- DW Strategy ;Strategy code offset
- ;
- ; 4) The Interrupt entry pointer -- Sixteen bit entry offset
- ; for the Interrupt code. As with the strategy code above,
- ; the Interrupt code must be in the same segment as the
- ; device header block.
- ;
- DW Interrupt;Interrupt code offset
- ;
- ; 5) An 8 byte block which, if a character driver, contains the
- ; name of the device driver padded with blanks. If a block mode
- ; driver, only the first byte is used to indicate how many
- ; separate devices are supported by this driver.
- ;
- DB 'SAMPLE ' ;Device name
- ;
- ;
- ;=================== REQUEST HEADER BLOCK ==============================
- ;
- ; When MS-DOS invokes a device driver, commands and data to the
- ; device driver are assembled into a Request header. A pointer
- ; to this data is passed to the device driver in the ES:BX register
- ; pair. Since the memory allocation is dynamic in this case, a
- ; block of equates must be allocated referenced to the above
- ; pointer. By far the easiest method of accessing this block
- ; of data is to use the Structure command for the MS assembler.
- ;
- Request equ ES:[DI] ;Set base address of Header block
- ;
- Reqhdr Struc
- Numb DB ? ;num of bytes in block -byte 0
- Unit DB ? ;unit number [block drivers] -byte 1
- Cmmd DB ? ;command byte -byte 2
- Stat DW ? ;return status -bytes 3-4
- Dos DB 4 dup(?);addr link used by DOS -bytes 5-8
- Intlnk DB 4 dup(?);linkage to other blocks -bytes 9-12
- ;
- ; After the above 'standard' locations, come the following
- ; locations in the Header block used for init, read and write
- ; operations.
- ;
- Media DB ? ;Media Descripter -byte 13
- Address DD ? ;Data transfer address -bytes 14-17
- Count DW ? ;Byte count value -bytes 18-19
- Reqhdr Ends
- ;
- ;=================== COMMAND OFFSET TABLE =============================
- ;
- ; Jump table for the commands passed in byte 2 (Cmmd) of the
- ; Request Header Block.
- ;
- Jumptbl:
- DW Allinit ;Init device driver # 0
- DW Exitt ;(media check) block command # 1
- DW Exitt ;(Build Bios Parm Block) # 2
- DW Exitt ;(IOCTL for input) not sup # 3
- DW Exitt ;(Input - read) not used # 4
- DW Exitt ;(Input non destructive) # 5
- DW Exitt ;(Input Status) # 6
- DW Exitt ;(Input Flush) # 7
- DW Outchar ;Output character # 8
- DW Outchar ;Output char with verify # 9
- DW Outstat ;Output status # 10
- DW Exitt ;(Output flush) # 11
- DW Exitt ;(IOCTL for output) # 12
- DW Exitt ;(Device open) # 13
- DW Exitt ;(Device close) # 14
- DW Exitt ;(Removable media) # 15
- ;
- ;
- ;=================== STRATEGY CODE BLOCK ===============================
- ;
- ; The sole purpose of the Strategy code is to accept and store
- ; the passed pointer to the Request Header Block. After MS-Dos
- ; calls the Strategy code in the correct device driver, it then
- ; calls the Interrupt code to execute the command.
- ;
- Savadd DD ? ;reserve a double word for the pointer
- ;
- ; Pointer to request header block is in ES:BX registers
- ; saved in Savadd area.
- ;
- Strategy proc far
- ;
- Mov CS:word ptr [Savadd],BX ;Save pointer address
- Mov CS:word ptr [Savadd + 2],ES
- Ret
- Strategy endp
- ;
- ;
- ;=================== INTERRUPT ROUTINES ===============================
- ;
- ; The Interrupt code area handles the actual work of the device
- ; driver. The command is decoded, then done, any errors are
- ; returned to MS-DOS. The pointer to the interrupt commands
- ; is contained in Savadd in the form OFFSET:Segment.
- ;
- Interrupt proc far
- ;
- Push AX ;save all registers
- Push BX
- Push CX
- Push DX
- Push BP
- Push SI
- Push DI
- Push DS
- Push ES
- Pushf
- ;
- Push CS ;Since we're in only one segment,
- Pop DS ;equate CS and DS making local data
- ;available
- ;
- Les DI,[Savadd] ;ES:DI = Request Header block pointer
- Xor BH,BH ;clear AH
- Mov BL,Request.Cmmd ;get the command byte
- ;
- Cmp BX,16 ;Check that command is in range
- Jle Exx ;OK
- Jmp Exitt ;Error exit
- ;
- Exx: Shl BX,1 ;Multiply by 2 and go to command
- ;
- Call Word ptr [BX+Jumptbl] ;Return AX = error status
- Jmp Exit ;Go back to MS-Dos
- ;
- Exitt: ;Unsupported commands
- Mov AX,3 ;Signal command error
- Or AX,8000H ;Add error bit
-
- Exit: ;Common exit return AX contains error status
- Les DI,[Savadd] ;Restore pointer
- Or AX,100H ;Set the done bit
- Mov Request.Stat,AX ;put error status in block
- Popf ;Restore all registers and flags
- Pop ES
- Pop DS
- Pop DI
- Pop SI
- Pop BP
- Pop DX
- Pop CX
- Pop BX
- Pop AX
- Ret ;Go back to MS-Dos
-
-
- Outchar proc near ;Output character(s) to printer
- ;
- Lds BX,[Request.Address] ;Get pointer to transferred data
- Mov CX,[Request.Count] ;Get byte transfer count
- ;
- Outlp: Mov AL,DS:[BX] ;Go get character
- Call Prntout ;Print it
- Inc BX ;Point to next character
- Dec CX ;Decrement character pointer
- Jnz Outlp ;Repeat until CX = 0
- ;
- ; Number of bytes passed is the number of bytes printed
- ; which is already in the proper location within the
- ; Request Header Block.
- ;
- Xor AX,AX ;No errors
- Ret ;Exit
- Outchar Endp
- ;
-
-
- Outstat proc near ;Get printer status
- ;
- Mov DX,Print_Stat ;Point to 'Input Status' Port
- In AL,DX ;Read the printer status
- Shl AX,1 ;Put busy status bit in proper location
- Shl AX,1
- Not AX ;Invert busy bit
- And AX,200H ;Clear all but busy bit
- Ret ;Go back
- Outstat Endp
- ;
- ;
- Prntout proc near ;Character output is in AL
- ;
- ;
- Mov DX,Print_Dat ;Address of 'Output Data' Port
- Out DX,AL ;Output the char to be printed
- ;
- ; Check the input status
- ;
- Mov DX,Print_Stat ;Address of 'Input Status' Port
- Wait: In AL,DX ;Read the printer status
- Test AL,Busy ;Check the busy bit
- Jz Wait ;Stay in loop until printer isn't busy
- ;
- ; When we reach here, the printer isn't busy
- ;
- Mov DX,Print_Out ;Address of 'Output control' port
- Mov AL,Strobe_Hi ;Strobe bit = 1
- Out DX,AL ;Strobe the printer
- Mov AL,Strobe_Low ;Strobe bit = 0
- Out DX,AL ;Turn Printer Strobe off
- Ret
- Prntout Endp
- ;
- Allinit proc near ;Called once, must return end address of
- ;code and proper status
- ;
- Mov Request.Address,offset Allinit ;End of program code
- Mov Request.Address+2,CS ;Segment
- Xor AX,AX ;no errors
- Ret
- Allinit endp
- ;
- Interrupt Endp
- Device Endp
- Code Ends
- End
-
-